﻿using System;
using System.Collections.Generic;

using CookComputing.XmlRpc;
using System.Web;
using System.IO;


namespace AnOtherBlog.Core.HttpHandlers
{
	/// <summary>
	/// Implementing the service that allows Web publishing from outside tools
	/// It uses the XML-RPC protocol (see http://www.xmlrpc.com/) implemented
	/// in an external DLL CookComputing.XmlRpc (see http://www.xml-rpc.net/)
	/// 
	/// I changed certain definitions of the MetaWeblog API interface to avoid
	/// conflicts with the basic classes in AnOtherBlog, CookComputing.XmlRpc need
	/// structures and public members, probably this can be solved with another 
	/// assembly and internal visibility, but I will always have to access
	/// the structures of MetaWeblog API as well as classes in AnOtherBlog.
	/// 
	/// 
	/// Implementación del Servicio web que permite publicar desde herramientas externas
	/// Utiliza el protocolo XML-RPC (ver http://www.xmlrpc.com/) que está implementado
	/// en un DLL externo CookComputing.XmlRpc (ver http://www.xml-rpc.net/)
	/// 
	/// He cambiado ciertas definiciones de la interfaz del MetaWeblog API para evitar
	/// conflictos con las clases básicas de AnOtherBlog, ocurre que CookComputing.XmlRpc
	/// necesita estructuras y miembros públicos, probablemente esto se pueda solucionar
	/// con otro ensamblado y visibilidad internal, pero siempre voy a tener que acceder
	/// a las estructuras del MetaWeblog API así como a las clases de AnOtherBlog.
	/// </summary>
	public class MetaWeblog : XmlRpcService, IMetaWeblog
	{

		#region Public Constructors

		public MetaWeblog()
		{
		}

		#endregion

		#region IMetaWeblog Interface Members
		#region MetaWeblog Members

		string IMetaWeblog.AddPost(string blogid, string username, string password, MetaWeblogPost mwpost, bool publish)
		{
			ValidateUser(username, password);

			Post post = new Post();

			post.Title = mwpost.title;
			post.PostContent = mwpost.description;
			post.Description = mwpost.mt_excerpt;			// revisar

			// TODO: Módulo de autores para cuando
			post.Author = "MetaWeblog API (" + username + ")";	// revisar

			post.IsCommentEnabled = true;
			post.IsPublished = publish;


			post.Save();
			
			return post.PostID.ToString();					
		}

		object IMetaWeblog.UpdatePost(string postid, string username, string password, MetaWeblogPost post, bool publish)
		{
			ValidateUser(username, password);
            
            Post oldpost = Post.Load(new Guid(postid));
            oldpost.Title = post.title;
            oldpost.PostContent = post.description;
            oldpost.Description = post.mt_excerpt;

            oldpost.Author = "MetaWeblog API (" + username + ")";

            oldpost.IsCommentEnabled = true;
            oldpost.IsPublished = publish;

            oldpost.Save();

			bool result = false;	// La versión anterior regresaba un bool, la nueva regresa on object ???
			return (object) result;
		}

		MetaWeblogPost IMetaWeblog.GetPost(string postid, string username, string password)
		{
			ValidateUser(username, password);

			Post post = Post.Load(new Guid(postid));
			
			MetaWeblogPost mwpost = SetMetaWeblogPostMembers(post);

			return mwpost;
		}

		/// <summary>
		/// Obtiene un arreglo con información sobre las categorías del blog
		/// </summary>
		/// <param name="blogid">Identificador del blog</param>
		/// <param name="username">Usuario</param>
		/// <param name="password">Password</param>
		/// <returns>Arreglo de <see cref="AnOtherBlog.Core.HttpHandlers.MetaWeblogCategoryInfo"/> información de categorías </returns>
		MetaWeblogCategoryInfo[] IMetaWeblog.GetCategories(string blogid, string username, string password)
		{
			ValidateUser(username, password);

			string webRoot = Util.WebRootAbsolute.ToString();
			MetaWeblogCategoryInfo[] mwCategories = new MetaWeblogCategoryInfo[Blog.Current.Categories.Count];
			for (int i = 0; i < Blog.Current.Categories.Count; ++i)
			{
				Category category = Blog.Current.Categories[i];
				
				mwCategories[i] = new MetaWeblogCategoryInfo();
				mwCategories[i].description = string.IsNullOrEmpty(category.Description) ? category.Description : category.CategoryName;
				string temp = webRoot + "category/" + category.CategoryID.ToString() + ".aspx";
				mwCategories[i].htmlUrl = temp;
				mwCategories[i].rssUrl = temp;
				mwCategories[i].title = category.CategoryName;
				mwCategories[i].categoryid = category.CategoryID.ToString();
			}
			return mwCategories;

		}

		MetaWeblogPost[] IMetaWeblog.GetRecentPosts(string blogid, string username, string password, int numberOfPosts)
		{
			ValidateUser(username, password);

			// Nos aseguramos de traer la lista completa de publicaciones sin proxy
			List<Post> posts = Post.LoadAll(Post.PostSort.DateCreated, false);
			int max = posts.Count;
			max = (numberOfPosts < max) ? numberOfPosts : max;

			MetaWeblogPost[] mwposts = new MetaWeblogPost[max];
			for (int i = 0; i < max; ++i)
			{
				mwposts[i] = SetMetaWeblogPostMembers(posts[i]);
			}
			posts.Clear();

			return mwposts;
		}

		MetaWeblogUrlData IMetaWeblog.NewMediaObject(string blogid, string username, string password, MetaWeblogFileData fileData)
		{
			ValidateUser(username, password);

			// TODO: Esto no debería estar fijo en el código
			string serverData = "~/App_Data/Files/";

			string serverPath = HttpContext.Current.Server.MapPath(serverData);

			string filePath = serverPath + Path.GetDirectoryName(fileData.name);
			string fileName = Path.GetFileName(fileData.name);
			if (!Directory.Exists(filePath))
			{
				Directory.CreateDirectory(filePath);
			}
			filePath += Path.DirectorySeparatorChar.ToString();

			FileStream fileStream = new FileStream(filePath + fileName, FileMode.Create);
			BinaryWriter binaryWriter = new BinaryWriter(fileStream);
			binaryWriter.Write(fileData.bits);
			binaryWriter.Close();

			string webRoot = Util.WebRootAbsolute.ToString() + "App_Data/Files/";

			//string fileType = fileData.type;
			//if (fileType.IndexOf('/') > -1)
			//{
			//  fileType = fileType.Substring(0, fileType.IndexOf('/'));
			//}
			//switch (fileType)
			//{
			//  case "image" :
			//  case "notsent" :
			//    webRoot += "image.axd?picture=";
			//    break;
			//  default :
			//    webRoot += "file.axd?file=";
			//    break;
			//}

			MetaWeblogUrlData urlData = new MetaWeblogUrlData();
			urlData.url = webRoot + fileData.name;
			return urlData;

		}

		#endregion

		#region Blogger API Members

		bool IMetaWeblog.DeletePost(string key, string postid, string username, string password, bool publish)
		{
			ValidateUser(username, password);

			bool result = false;
			// TODO: Implement your own logic to delete the post and set the result
			return result;
		}

		/// <summary>
		/// Obtiene información de los blogs de un usuario en particular
		/// </summary>
		/// <param name="key">Clave de negocio (no se utiliza)</param>
		/// <param name="username">Usuario</param>
		/// <param name="password">Password</param>
		/// <returns>Arreglo con la información de los blogs del usuario</returns>
		MetaWeblogBlogInfo[] IMetaWeblog.GetUsersBlogs(string key, string username, string password)
		{
			// TODO: Analizar si un usuario puede o no ser autor de varios blogs en la aplicación !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
			ValidateUser(username, password);

			MetaWeblogBlogInfo[] infos = new MetaWeblogBlogInfo[1];

			infos[0] = new MetaWeblogBlogInfo();
			infos[0].blogid = Blog.Current.BlogID.ToString();
			infos[0].blogName = Blog.Current.BlogSettings.Name;
			infos[0].url = Util.WebRootAbsolute.ToString();

			return infos;
		}

		MetaWeblogUserInfo IMetaWeblog.GetUserInfo(string key, string username, string password)
		{
			ValidateUser(username, password);

			MetaWeblogUserInfo info = new MetaWeblogUserInfo();
			// TODO: Implement your own logic to get user info objects and set the info
			return info;
		}

		#endregion
		#endregion

		#region Private Methods

		private void ValidateUser(string username, string password)
		{
			// TODO: Aquí hay que verificar que username está habilitado como autor en el blog caso contrario hay que producir la excepción
			//throw new XmlRpcFaultException(0, "User is not valid!");
		}

		/// <summary>
		/// Fija los miembros de la estructura MetaWeblogPost de
		/// acuerdo a los valores del objeto Post
		/// </summary>
		/// <param name="post">Publicación</param>
		/// <returns>estructura MetaWeblogPost</returns>
		private MetaWeblogPost SetMetaWeblogPostMembers(Post post)
		{
			MetaWeblogPost mwpost = new MetaWeblogPost();

			mwpost.dateCreated = post.DateCreated;
			mwpost.description = post.PostContent;
			mwpost.title = post.Title;

			string[] mwCategories = new string[post.Categories.Count];
			for (int i = 0; i < post.Categories.Count; ++i)
			{
				mwCategories[i] = post.Categories[i].CategoryName;
			}

			//mwpost.enclosure = new MetaWeblogEnclosure();

			mwpost.link = post.LinkAbsolute.AbsoluteUri;
			mwpost.permalink = mwpost.link; // revisar				

			mwpost.postid = post.PostID.ToString();
			//mwpost.source = new MetaWeblogSource();
			mwpost.userid = "na";

			//mwpost.mt_allow_comments = new object();
			//mwpost.mt_allow_pings = new object();
			//mwpost.mt_convert_breaks = new object();

			mwpost.mt_text_more = "[more]";
			mwpost.mt_excerpt = post.Description;
			mwpost.wp_slug = post.Slug;

			return mwpost;
		}

		///// <summary>
		///// Escribre una cadena de texto en el archivo de log
		///// </summary>
		///// <param name="strText">Cadena de texto a escribir en el log</param>
		///// <param name="isAppend">Modo de escritura: true=Agrega, false=Sobreescribe</param>
		//void WriteLog(string strText, bool isAppend)
		//{
		//  string fileName = System.Web.HttpContext.Current.Server.MapPath("~/App_Data/MetaWeblog.txt");
		//  System.IO.StreamWriter writer = new System.IO.StreamWriter(fileName, isAppend);
		//  writer.WriteLine(DateTime.Now.ToString() + ", " + strText);
		//  writer.Close();
		//}

		#endregion
	}

}
